﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace hamster
{
    class ObjectPlacer
    {
        // Per degree chance of an object
        public const float PLANT_SPARCITY = 0.2f;
        public const float ROCK_SPARCITY = 0.3f;
        public const float ROCK_PLACEMENT = 0.3f;
        public const float FRUIT_SPARCITY = 0.3f;
        public const float PLANT_CHANCE = 0.3f;
        public const float GROUND_ROCK = .5f;
        public const float WASTE_TIME = 14f;
        public const float PLANT_CHANCE_DECREASE_RATE = .2f;

        public HashSet<WasteGoomba> activeWaste_;
        public HashSet<Plant> activePlants_;
        public HashSet<Rock> activeRocks_;
        public HashSet<Fruit> activeFruit_;
        public HashSet<Powerup> activePowerups_;

        public static Effect _objectEffect;
        public static Effect _enemyEffect;
        public static Texture2D _leaf;
        public static Texture2D _leaf_b;
        public static Texture2D _fruit;
        public static Texture2D _fruit_glow;
        public static Texture2D _enemy;
        public static Texture2D _enemy_glow;
        public static Texture2D _enemy_ballon;
        public static VertexPositionNormalTexture[] _quad = new VertexPositionNormalTexture[] {

                new VertexPositionNormalTexture { Position = new Vector3(-1f, -1f, 0f), TextureCoordinate = new Vector2(0,1) },
                new VertexPositionNormalTexture { Position = new Vector3(1f, -1f, 0f), TextureCoordinate = new Vector2(1,1) },
                new VertexPositionNormalTexture { Position = new Vector3(1f, 1f, 0f), TextureCoordinate = new Vector2(1,0) },

                new VertexPositionNormalTexture { Position = new Vector3(-1f, -1f, 0f), TextureCoordinate = new Vector2(0,1) },
                new VertexPositionNormalTexture { Position = new Vector3(1f, 1f, 0f), TextureCoordinate = new Vector2(1,0) },
                new VertexPositionNormalTexture { Position = new Vector3(-1f, 1f, 0f), TextureCoordinate = new Vector2(0,0) },
            };

        public float wasteDumpTimer_;

        public static float plantChance_ = PLANT_CHANCE;

        Game1 parent_;

        public void ReloadContent(ContentManager content)
        {
            if (_leaf != null) _leaf.Dispose();
            if (_leaf_b != null) _leaf_b.Dispose();
            if (_fruit != null) _fruit.Dispose();
            if (_fruit_glow != null) _fruit_glow.Dispose();
            if (_enemy != null) _enemy.Dispose();
            if (_enemy_glow != null) _enemy_glow.Dispose();
            if (_enemy_ballon != null) _enemy_ballon.Dispose();

            if (_objectEffect != null) _objectEffect.Dispose();

            _leaf = content.Load<Texture2D>("leaf_a");
            _leaf_b = content.Load<Texture2D>("leaf_b");
            _fruit = content.Load<Texture2D>("fruit");
            _fruit_glow = content.Load<Texture2D>("fruit_glow");

            _enemy = content.Load<Texture2D>("enemy");
            _enemy_glow = content.Load<Texture2D>("enemy_glow");
            _enemy_ballon = content.Load<Texture2D>("enemy_ballon");

            _objectEffect = content.Load<Effect>("Objects");
            _enemyEffect = content.Load<Effect>("shader_Enemy");
        }

        public ObjectPlacer(Game1 parent)
        {
            parent_ = parent;
            wasteDumpTimer_ = WASTE_TIME + Game1.RandomNegPos() * WASTE_TIME / 2;
        }

        public void Initialise()
        {
            activeFruit_ = new HashSet<Fruit>();
            activePlants_ = new HashSet<Plant>();
            activePowerups_ = new HashSet<Powerup>();
            activeRocks_ = new HashSet<Rock>();
            activeWaste_ = new HashSet<WasteGoomba>();

            placeInitialObjects();
        }

        private void placeInitialObjects()
        {
            float circumference = MathHelper.TwoPi * Wheel.RADIUS_IN;

            // Adding plants
            float plantGap = MathHelper.TwoPi / (circumference * PLANT_SPARCITY);
            float sumAngle = 0;
            Vector2 startPosition = new Vector2(0, -(Wheel.RADIUS_IN * 1f + Wheel.RADIUS_OUT * 0f));
            while (sumAngle < MathHelper.TwoPi)
            {
                sumAngle += plantGap / 2 + (float)Game1.random.NextDouble() * plantGap;
                Matrix rotationMatrix = Matrix.CreateRotationZ(sumAngle);
                Vector2 rotatedPosition = Vector2.Transform(startPosition, rotationMatrix);
                Plant plant = new Plant(rotatedPosition, sumAngle - (float)Math.PI, this);
                activePlants_.Add(plant);

                // Add fruit
                //while (Game1.random.NextDouble() < FRUIT_SPARCITY)
                //{
                //    // Spawn fruit
                //    Fruit fruit = plant.SpawnFruit();
                //    activeFruit_.Add(fruit);
                //}
            }

            // Adding rocks
            //float rockGap = MathHelper.TwoPi / (circumference * ROCK_SPARCITY);
            //sumAngle = 0;
            //startPosition = new Vector2(0, -(Wheel.RADIUS_IN * 0.7f + Wheel.RADIUS_OUT * 0.3f));
            //while (sumAngle < MathHelper.TwoPi)
            //{
            //    Vector2 thisPos = new Vector2(startPosition.X, startPosition.Y);
            //    sumAngle += rockGap / 2 + (float)Game1.random.NextDouble() * rockGap;
            //    Matrix transformationMatrix = Matrix.Identity;
            //    if (Game1.random.NextDouble() >= GROUND_ROCK)
            //        transformationMatrix *= Matrix.CreateScale(new Vector3(0, (1 - (float)Game1.random.NextDouble() * ROCK_PLACEMENT), 0));
            //    transformationMatrix *= Matrix.CreateRotationZ(sumAngle);
            //    Vector2 rotatedPosition = Vector2.Transform(startPosition, transformationMatrix);
            //    Rock rock = new Rock(rotatedPosition, sumAngle - (float)Math.PI, this);
            //    activeRocks_.Add(rock); 
            //}
        }

        public void CreateWaste(Player player)
        {
            WasteGoomba waste = new WasteGoomba(new Vector2(player.position.X, player.position.Y), player.rotation, this);
            activeWaste_.Add(waste);
        }

        internal void Update(float dt, Player player)
        {
            plantChance_ -= dt * PLANT_CHANCE_DECREASE_RATE;
            /*wasteDumpTimer_ -= dt;
            if (wasteDumpTimer_ <= 0)
            {
                Waste waste = new Waste(new Vector2(player.position.X, player.position.Y), player.rotation, this);
                activeWaste_.Add(waste);
                wasteDumpTimer_ = WASTE_TIME + Game1.RandomNegPos() * WASTE_TIME / 2;
            }*/

            // Fruit
            activeFruit_.RemoveWhere(delegate(Fruit f) { return f.Update(dt, player); });

            // Powerup
            activePowerups_.RemoveWhere(delegate(Powerup p) { return p.Update(dt, player); });

            // Plant
            activePlants_.RemoveWhere(delegate(Plant p) { return p.Update(dt, player); });

            // Waste
            activeWaste_.RemoveWhere(delegate(WasteGoomba w) { return w.Update(dt, player); });

            // Rock
            //activeRocks_.RemoveWhere(delegate(Rock r) { return r.Update(dt, player); });
        }

        internal void Draw(GraphicsDevice device)
        {
            //return;
            _objectEffect.Parameters["View"].SetValue(Game1.viewMatrix);
            _objectEffect.Parameters["Projection"].SetValue(Game1.projectionMatrix);
            _objectEffect.Parameters["UserTexture"].SetValue(_leaf);
            _objectEffect.Parameters["LeafTextureB"].SetValue(_leaf_b);
            _objectEffect.Parameters["Time"].SetValue(Game1.time_duration);

            device.RenderState.DepthBufferWriteEnable = false;
            device.RenderState.AlphaBlendEnable = true;
            device.RenderState.SourceBlend = Blend.SourceAlpha;
            device.RenderState.DestinationBlend = Blend.InverseSourceAlpha;

            _objectEffect.Begin();
            _objectEffect.CurrentTechnique.Passes[0].Begin();
            foreach (Plant p in activePlants_)
            {
                p.Draw(device);
            }
            _objectEffect.CurrentTechnique.Passes[0].End();
            _objectEffect.End();

            _objectEffect.Begin();
            _objectEffect.Parameters["UserTexture"].SetValue(_fruit);
            _objectEffect.CurrentTechnique.Passes[1].Begin();
            foreach (Fruit f in activeFruit_)
            {
                f.Draw(device);
            }
            _objectEffect.CurrentTechnique.Passes[1].End();

            /*MAKE FRUIT GLOW*/
            #region

            device.RenderState.AlphaBlendEnable = true;
            device.RenderState.AlphaSourceBlend = Blend.One;
            device.RenderState.AlphaDestinationBlend = Blend.One;
            //device.RenderState.SourceBlend = Blend.One;
            device.RenderState.DestinationBlend = Blend.One;
            device.RenderState.BlendFunction = BlendFunction.Add;

            _objectEffect.Parameters["UserTexture"].SetValue(_fruit_glow);
            _objectEffect.CurrentTechnique.Passes[2].Begin();
            foreach (Fruit f in activeFruit_)
            {
                float upscale = 0.25f;
                f.objectScale_ += upscale;
                f.Draw(device);
                f.objectScale_ -= upscale;
            }
            _objectEffect.CurrentTechnique.Passes[2].End();

            #endregion
            /*MAKE FRUIT GLOW*/

            _objectEffect.End();

            _enemyEffect.Parameters["glow"].SetValue(1);
            _enemyEffect.Parameters["View"].SetValue(Game1.viewMatrix);
            _enemyEffect.Parameters["Projection"].SetValue(Game1.projectionMatrix);
            _enemyEffect.Parameters["Time"].SetValue(Game1.time_duration);

            _enemyEffect.Begin();
            device.RenderState.SourceBlend = Blend.SourceAlpha;
            device.RenderState.DestinationBlend = Blend.InverseSourceAlpha;
            _enemyEffect.Parameters["UserTexture"].SetValue(_enemy);
            _enemyEffect.CurrentTechnique.Passes[0].Begin();
            foreach (WasteGoomba w in activeWaste_)
            {
                w.Draw(device);
            }
            _enemyEffect.CurrentTechnique.Passes[0].End();


            _enemyEffect.Parameters["UserTexture"].SetValue(_enemy_ballon);
            _enemyEffect.CurrentTechnique.Passes[0].Begin();
            foreach (WasteGoomba w in activeWaste_)
            {
                w.DrawBallon(device);
            }
            _enemyEffect.CurrentTechnique.Passes[0].End();
            
            //GLOW

            device.RenderState.AlphaSourceBlend = Blend.One;
            device.RenderState.AlphaDestinationBlend = Blend.One;
            //device.RenderState.SourceBlend = Blend.One;
            device.RenderState.DestinationBlend = Blend.One;
            device.RenderState.BlendFunction = BlendFunction.Add;
            _enemyEffect.Parameters["UserTexture"].SetValue(_enemy_glow);
            _enemyEffect.CurrentTechnique.Passes[1].Begin();
            foreach (WasteGoomba w in activeWaste_)
            {
                w.DrawGlow(device);
            }
            _enemyEffect.CurrentTechnique.Passes[1].End();
            //GLOW

            _enemyEffect.End();
            device.RenderState.DepthBufferWriteEnable = true;
            device.RenderState.AlphaBlendEnable = false;
        }
    }
}
